import { useCallback, useEffect, useState } from "react";
import './index.css'
import classname from "classnames";
import { Box1, Box2 } from '../../../components/dialog/reddem';
import { useWorkspace } from "../../workspace";
import { PublicKey, SYSVAR_RENT_PUBKEY, SystemProgram } from "@solana/web3.js";
import { config } from "../../utils/config"
import { ASSOCIATED_PROGRAM_ID, TOKEN_PROGRAM_ID, associatedAddress } from "@coral-xyz/anchor/dist/cjs/utils/token";
import BN from "bn.js";
import { AnchorError } from "@coral-xyz/anchor/dist/cjs/error";
import { safeDivide, preciseToInteger,restoreOriginalValue,preciseSubtraction ,compareValues,calculate} from "../../utils/bignum";
import { Success, Error, Close, Earnings } from "web/src/components/dialog/message";
import { Console } from "console";
import { Loading } from '../../../components/loading/index'
import Big from 'big.js';
interface StakeData {
  tokenStaked: string;
}

interface PoolData {
  tokenStaked: string;
}

interface EarnData {
  num: string;
}
interface ShowEarn{
  dt?: string
  dd?: string
}

function validateTokenAmount(input: string, decimals: number): boolean {
  // 检查是否是有效的数字并且符合小数位数的要求
  const regex = new RegExp(`^\\d*(\\.\\d{0,${decimals}})?$`);
  if (!regex.test(input)) {
      return false;
  }

  // 确保小数点不多于一个
  const parts = input.split('.');
  if (parts.length > 2) {
      return false;
  }

  return true;
}



export default function HomePage() {
  const [ showSuccess, setShowSuccess ] = useState('')
  const [ showError, setShowError ] = useState('')
  const [ showClose, setShowClose ] = useState('')
  const [ isEmpty, setIsEmpty ] = useState(false)
  const [ showLoading, setShowLoading] = useState(false)

  const [ showEarnings, setShowEarnings ] = useState<ShowEarn | null>(null)

  const toggleEarnings = (obj: ShowEarn | null) =>{
    setShowEarnings(obj)
  }

  const showToastSuccess = (text: string) =>{
    setShowSuccess(text)
    setTimeout(() =>{
      setShowSuccess('')
    },2000)
  }
  const showToastError = (text: string) =>{
    setShowError(text)
    setTimeout(() =>{
      setShowError('')
    },2000)
  }
  const showToastClose = (text: string) =>{
    setShowClose(text)
    setTimeout(() =>{
      setShowClose('')
    },2000)
  }
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const inputValue = e.target.value;
    const decimals = config.lpDecimals;
    // 验证输入是否合法
    if (validateTokenAmount(inputValue, decimals)) {
        //setIsValid(true);
        //setValue(inputValue);
        setStakeAmount(inputValue);
    } else {
        //setIsValid(false);
    }
  };

  const [ showbox1, setShowbox1 ] = useState(false);
  //const [ showbox2, setShowbox2 ] = useState(false);
  const [stakeAmount, setStakeAmount] = useState<string>(''); // Stake amount state

  const toggleBox1 = (show: boolean) => {
    if(work && work.wallet){
      view();
    }else{

        const walletBtn:any = document.querySelector('.wallet-adapter-button')
          console.log(walletBtn)
          walletBtn.click()

    }
    // setShowbox1(show);
  };
  const verifEmpry = () =>{
    return new Promise((resolve) =>{
      if( stakeAmount ){
        resolve(false)
        setIsEmpty(false)
      }else{
        setIsEmpty(true)
      }
    })
  }
  const stakeSumbit = async () => {
    await verifEmpry()
    if(work && work.wallet){
      stakeToken();
    }else{
      const walletBtn:any = document.querySelector('.wallet-adapter-button')
        console.log(walletBtn)
        walletBtn.click()
    }

  };

  const redeemSumbit= async () => {
    await verifEmpry()
    if(work && work.wallet){
      unStakeToken();
    }else{
      const walletBtn:any = document.querySelector('.wallet-adapter-button')
        console.log(walletBtn)
        walletBtn.click()
    }
  };

  const withdrewSumbit= () => {
    if(work && work.wallet){
      withdrew();
    }else{
      const walletBtn:any = document.querySelector('.wallet-adapter-button')
        console.log(walletBtn)
        walletBtn.click()
    }
  };

  const work = useWorkspace();
  const [stake, setStake] = useState<StakeData | null>(null);
  const [pool, setPool] = useState<PoolData | null>(null);
  const [earn, setEarn] = useState<EarnData | null>(null);
  const [isPreSale, setIsPreSale] = useState<EarnData | null>(null);

  const getData = useCallback(async () => {
    setShowLoading(true)
    try {
      //console.log(work.wallet);
      if (work && work.wallet) {

        const { program, provider } = work;
        const user = provider.wallet.publicKey;
        //pool
        const pledge_pool = PublicKey.findProgramAddressSync([Buffer.from("pledge_pool")], program.programId)[0];
        const totalAccounts = await program.account.pledgePool.fetch(pledge_pool);
        console.log("totalAccounts", totalAccounts);
        const poolamount = restoreOriginalValue(totalAccounts.tokenStaked, config.lpDecimals);
        const poolResults: PoolData = { tokenStaked: poolamount.toString() };
        setPool(poolResults);
        //user
        const pledge_user = PublicKey.findProgramAddressSync([user.toBuffer()], program.programId)[0];
        console.log(pledge_user);
        const stakeInfoAccounts = await program.account.pledgeUser.fetch(pledge_user);
        console.log("stakeInfoAccounts", stakeInfoAccounts);
        if (stakeInfoAccounts) {
          const useamount = restoreOriginalValue(stakeInfoAccounts.tokenAmount,config.lpDecimals)
          const newredResults: StakeData = {
            tokenStaked: useamount.toString(),
          };
          setStake(newredResults);
        } else {
          const newredResults: StakeData = { tokenStaked: "0" };
          setStake(newredResults);
        }
        setShowLoading(false)
      }
    } catch (error) {
      setShowLoading(false)
      const newredResults: StakeData = { tokenStaked: "0" };
      setStake(newredResults);
      const poolResults: PoolData = { tokenStaked: "0" };
      setPool(poolResults);
      console.error('Failed to load data:', error);
    }
  }, [work]);

  useEffect(() => {
    getData();
  }, [getData]);

  const stakeToken = async () => {
    const { program, provider,connection } = work;
    setShowLoading(true)
    //console.log("Staking amount:", stakeAmount);
    // 添加你的质押逻辑
    const lpmint = new PublicKey(config.lpToken);//lptoken

          const amountValue = preciseToInteger(stakeAmount, config.lpDecimals);
          console.log(amountValue);
         //判断代币是否存在
         try {

          const pay = await connection.getParsedAccountInfo(lpmint);

            const tokenData = pay.value.data.parsed.info;

            if(!tokenData.isInitialized){
              console.error('代币未初始化');
            }

            //console.log(amountValue);
            const owner = provider.wallet.publicKey;
            console.log(tokenData);
            const userVault = associatedAddress({
                mint: lpmint,
                owner: owner
              });
              //console.log(userVault);

              const findAccountARes = await connection.getTokenAccountBalance(userVault);

              const findAccountValue = findAccountARes.value.amount;
              console.log(findAccountValue)
              const intValue = new BN(findAccountValue);
              console.log(intValue)
              // if(intValue<amountValue){
              //   console.error('余额不足');
              //   showToastClose('Insufficient Balance')
              // }

              // 使用 lt 方法比较
              if (intValue.lt(amountValue)) {
                console.error('余额不足');
                setShowLoading(false)
                showToastClose('Insufficient Balance')
              }else{
                const user = provider.wallet.publicKey;
                const lp_pool = PublicKey.findProgramAddressSync([Buffer.from("lp_pool"), lpmint.toBuffer()], program.programId)[0];//用户质押池
                const ray_config = PublicKey.findProgramAddressSync([Buffer.from("ray_config"), lpmint.toBuffer()], program.programId)[0];//raydium 配置
                const pledge_pool = PublicKey.findProgramAddressSync([Buffer.from("pledge_pool")], program.programId)[0];//质押池
                const pledge_user = PublicKey.findProgramAddressSync([user.toBuffer()], program.programId)[0];//用户质押地址
                const pledge_amount = new BN(amountValue);//100 token 质押数量

                const user_token =  associatedAddress({
                  mint: lpmint,
                  owner: user
                });//用户token地址
                console.log("pledge_amount",pledge_amount.toString());
                console.log("user",user.toBase58());
                console.log("lp_pool",lp_pool.toBase58());
                console.log("pledge_pool",pledge_pool.toBase58());
                console.log("pledge_user",pledge_user.toBase58());


                try {

                  const tx = await program.methods
                  .pledgeToken(pledge_amount)
                  .accounts({
                    user: user,//用户
                    rayConfig: ray_config,//raydium 配置账户
                    mint: lpmint,//初始化的token mint
                    userToken: user_token,//用户token地址
                    lpPool: lp_pool,//用户质押池
                    pledgePool: pledge_pool,//质押池
                    pledgeUser: pledge_user,//用户质押地址
                    systemProgram: SystemProgram.programId,
                    tokenProgram: TOKEN_PROGRAM_ID,
                    associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
                    rent: SYSVAR_RENT_PUBKEY,
                  })
                  .signers([])
                  .rpc();

                  console.log("Your transaction signature", tx);
                  setShowLoading(false)
                  showToastSuccess('Stake Success');
                  //update state
                  let stakefinal = Number(stakeAmount);
                  let poolfinal = Number(stakeAmount);

                  if (stake && stake.tokenStaked && stake.tokenStaked !== "0") {
                      stakefinal = stakefinal+Number(stake.tokenStaked);
                  }

                  if (pool && pool.tokenStaked && pool.tokenStaked !== "0") {
                    poolfinal = poolfinal+Number(pool.tokenStaked);
                  }

                  setStake({tokenStaked:stakefinal.toString()});
                  setPool({tokenStaked:poolfinal.toString()});


               } catch (error) {

                 if (error instanceof AnchorError) {

                   showToastError("Stake Fail");
                   const code = error.error.errorCode.code ;
                   const number = error.error.errorCode.number ;
                   const  message = error.error.errorMessage;
                   setShowLoading(false)
                   console.error('捕获到的错误: ', code,number,message);
                   // 在这里处理错误，例如显示错误消息给用户
                 } else {
                   // 处理其他类型的错误
                   setShowLoading(false)
                   console.error('未知错误: ', error);
                 }
               }
              }

        } catch (error) {

          console.error('你还没有此代币');
        }

  };

  const unStakeToken = async () => {
    const { program, provider,connection } = work;

    setShowLoading(true)
    // 添加你的质押逻辑
    const lpmint = new PublicKey(config.lpToken);//lptoken
          if(stake?.tokenStaked)
          {
            const stakeAmountnow = stake.tokenStaked;
            //console.log(stakeAmountnow,amountValue)

            const comparisonResult = compareValues(stakeAmount, stakeAmountnow);
            if (comparisonResult === 1) {

                console.log(stakeAmountnow,stakeAmount)
                showToastClose('No enough stake')
                setShowLoading(false)
            } else  {

                   //判断代币是否存在
                   try {

                    const pay = await connection.getParsedAccountInfo(lpmint);

                      const tokenData = pay.value.data.parsed.info;

                      if(!tokenData.isInitialized){
                        console.error('代币未初始化');
                      }

                  } catch (error) {
                    console.error('fetch lp error');
                  }
                  const unpledge_amount = preciseToInteger(stakeAmount, config.lpDecimals);
                  const user = provider.wallet.publicKey;
                  const lp_pool = PublicKey.findProgramAddressSync([Buffer.from("lp_pool"), lpmint.toBuffer()], program.programId)[0];//用户质押池
                  const ray_config = PublicKey.findProgramAddressSync([Buffer.from("ray_config"), lpmint.toBuffer()], program.programId)[0];//raydium 配置
                  const pledge_pool = PublicKey.findProgramAddressSync([Buffer.from("pledge_pool")], program.programId)[0];//质押池
                  const pledge_user = PublicKey.findProgramAddressSync([user.toBuffer()], program.programId)[0];//用户质押地址
                  //const unpledge_amount = new BN(amountValue);//100 token 质押数量

                  const user_token =  associatedAddress({
                    mint: lpmint,
                    owner: user
                  });//用户token地址


                  try {

                    const tx = await program.methods
                    .unpledgeToken(unpledge_amount)
                    .accounts({
                      user: user,
                      rayConfig:ray_config,
                      mint: lpmint,
                      userToken: user_token,
                      lpPool: lp_pool,
                      pledgePool: pledge_pool,
                      pledgeUser: pledge_user,
                      systemProgram: SystemProgram.programId,
                      tokenProgram: TOKEN_PROGRAM_ID,
                      associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
                      rent: SYSVAR_RENT_PUBKEY,
                    })
                    .signers([])
                    .rpc();
                    console.log("Your transaction signature", tx);
                    setShowLoading(false)
                    showToastSuccess('Untake Success');
                    //update state
                    let stakefinal = "0";
                    let poolfinal = "0";

                    if (stake && stake.tokenStaked && stake.tokenStaked !== "0") {
                        //stakefinal = Number(stake.tokenStaked) - stakefinal;
                        stakefinal = preciseSubtraction(stake.tokenStaked,stakeAmount);
                    }

                    if (pool && pool.tokenStaked && pool.tokenStaked !== "0") {
                      //poolfinal = Number(pool.tokenStaked) - poolfinal;
                      poolfinal = preciseSubtraction(pool.tokenStaked,stakeAmount);

                    }

                    setStake({tokenStaked:stakefinal.toString()});
                    setPool({tokenStaked:poolfinal.toString()});



                } catch (error) {

                  if (error instanceof AnchorError) {

                      showToastError("UnStake Fail");
                    const code = error.error.errorCode.code ;
                    const number = error.error.errorCode.number ;
                    const  message = error.error.errorMessage;
                    setShowLoading(false)
                    console.error('捕获到的错误: ', code,number,message);
                    // 在这里处理错误，例如显示错误消息给用户
                  } else {
                    setShowLoading(false)
                    // 处理其他类型的错误
                    console.error('未知错误: ', error);
                  }
                }
            }


          }else{
            setShowLoading(false)
            showToastClose('No Stake');
          }



  };

  const view = async () => {
    const { program, provider,connection } = work;
    setShowLoading(true)
    // // 添加你的质押逻辑
    const mint = new PublicKey(config.lpToken);//lptoken

         //判断代币是否存在
         try {

          const pay = await connection.getParsedAccountInfo(mint);

            const tokenData = pay.value.data.parsed.info;

            if(!tokenData.isInitialized){
              console.error('代币未初始化');
            }

        } catch (error) {
          console.error('fetch lp error');
        }

        try {
          const { program, provider } = work;
          const user = provider.wallet.publicKey;
          const pledge_user = PublicKey.findProgramAddressSync([user.toBuffer()], program.programId)[0];
          const pledge_pool = PublicKey.findProgramAddressSync([Buffer.from("pledge_pool")], program.programId)[0];
          const totalAccounts = await program.account.pledgePool.fetch(pledge_pool);
          console.log("totalAccounts", totalAccounts);
          const stakeInfoAccounts = await program.account.pledgeUser.fetch(pledge_user);
          console.log("stakeInfoAccounts", stakeInfoAccounts);

          const tokenAccRatio = totalAccounts.tokenAccRatio.toString();
          const nftAccRatio = totalAccounts.nftAccRatio.toString();

          console.log("nftAccRatio",nftAccRatio);

          let num = new BN(0);
          if (stakeInfoAccounts) {


            const tokenAmount = stakeInfoAccounts.tokenAmount;
            console.log("tokenAmount",tokenAmount.toString());
            console.log("tokenAccRatio",tokenAccRatio);
            const tokenDebt = stakeInfoAccounts.tokenDebt;
            console.log("tokenDebt",tokenDebt.toString());
            const tokenRemaining = stakeInfoAccounts.tokenRemaining;
            console.log("tokenRemaining",tokenRemaining.toString());


            const nftAmount = stakeInfoAccounts.nftAmount;
            console.log("nftAmount",nftAmount.toString());
            const nftDebt = stakeInfoAccounts.nftDebt;
            console.log("nftDebt",nftDebt.toString());
            const nftRemaining = stakeInfoAccounts.nftRemaining;



           num = calculate(
              tokenAmount, tokenAccRatio, tokenDebt, tokenRemaining,
              nftAmount, nftAccRatio, nftRemaining, nftDebt
            );



          }

          //const num_string = num.toString();

          const num_ui = restoreOriginalValue(num,config.lpDecimals);

          console.log(num_ui);
          setEarn({num:num_ui});
          setShowLoading(false)
            toggleEarnings({
              dt: 'Current Income： ',
              dd: num_ui
            })

       } catch (error) {
          setShowLoading(false)
          toggleEarnings({
            dt: 'Current Income： ',
            dd: '0'
          })

         if (error instanceof AnchorError) {


           const code = error.error.errorCode.code ;
           const number = error.error.errorCode.number ;
            const  message = error.error.errorMessage;
            setShowLoading(false)
           console.error('捕获到的错误: ', code,number,message);
           // 在这里处理错误，例如显示错误消息给用户
         } else {
            setShowLoading(false)
           // 处理其他类型的错误
           console.error('未知错误: ', error);
         }
       }


  };



  const withdrew = async () => {
    const { program, provider,connection } = work;

    const mint = new PublicKey(config.token);//lptoken
    console.log("mint",mint);
    console.log("programid",program.programId);
    setShowLoading(true)
         //判断代币是否存在
         try {

            const pay = await connection.getParsedAccountInfo(mint);

            const tokenData = pay.value.data.parsed.info;

            if(!tokenData.isInitialized){
              console.error('代币未初始化');
            }

        } catch (error) {
          console.error('fetch token error');
        }

        const user = provider.wallet.publicKey;
        const user_token =  associatedAddress({
          mint: mint,
          owner: user
        });
        const fund_pool = PublicKey.findProgramAddressSync([Buffer.from("fund_pool"), mint.toBuffer()], program.programId)[0];
        const pledge_pool = PublicKey.findProgramAddressSync([Buffer.from("pledge_pool")], program.programId)[0];
        const pledge_user = PublicKey.findProgramAddressSync([user.toBuffer()], program.programId)[0];

        try {
          const tx = await program.methods
            .drawProfit()
            .accounts({
                user: user,
                mint: mint,
                pledgePool: pledge_pool,
                pledgeUser: pledge_user,
                fundPool: fund_pool,
                userToken: user_token,
                tokenProgram: TOKEN_PROGRAM_ID,
                systemProgram: SystemProgram.programId,
                associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
                rent: SYSVAR_RENT_PUBKEY,
            })
            .signers([])
            .rpc();
          console.log("Your transaction signature", tx);
          showToastSuccess('Earn Success');
          setShowLoading(false)
       } catch (error) {

         if (error instanceof AnchorError) {
          setShowLoading(false)
          showToastError("Earn Fail");
           const code = error.error.errorCode.code ;
           const number = error.error.errorCode.number ;
            const  message = error.error.errorMessage;

           console.error('捕获到的错误: ', code,number,message);
           // 在这里处理错误，例如显示错误消息给用户
         } else {
           // 处理其他类型的错误
           setShowLoading(false)
           console.error('未知错误: ', error);
         }
       }


  };




  return (
    <div className="grid-width">
      <div className="lp-card">
        <div className="lp-h4">
          <div className="lp-h4-bar"></div>
          LP impawn
          <img src="../../../assets/audio.png" className="lp-h4-icon" alt="" />
        </div>
        <div className="lp-main">
          <div className="lp-text">Current LP：{stake?.tokenStaked}</div>
          <input
            type="text"
            className={classname({
              'lp-input': true,
              'lp-input-empty': isEmpty
            })}
            placeholder="Please enter the amount to Stake or UnStake"
            value={stakeAmount}
            //onChange={(e) => setStakeAmount(e.target.value)}
            onChange={handleChange}
          />
          <div className="lp-footer">
            <div onClick={() => stakeSumbit()} className="lp-btn">Stake now</div>
            <div onClick={() => redeemSumbit()} className="lp-btn">Redeem</div>
          </div>
        </div>
      </div>

      <div className="lp-card">
        <div className="lp-h4">
          <div className="lp-h4-bar"></div>
          LP earnings
          <img src="../../../assets/audio.png" className="lp-h4-icon" alt="" />
        </div>
        <div className="lp-main2">
          <div className="lp-box-hd">
            Total LP of the whole network
            {pool?.tokenStaked && <div className="lp-box-hd-bar">{pool?.tokenStaked}</div>}
          </div>
          <div className="lp-box-bd">
            <div onClick={() => toggleBox1(true)} className="lp-box-btn">View revenue</div>
            <div onClick={() => withdrewSumbit()} className="lp-box-btn lp-box-btn-primary">Extract</div>
          </div>
        </div>
      </div>
      <div className="lp-footer">
        <img className="lp-footer-p" src="../../../assets/p.png" alt="../../../assets/p.png" />
        <img className="lp-footer-j" src="../../../assets/j.png" alt="../../../assets/j.png" />
      </div>

      {/* {showbox1 && (
        <Box1
          data={{
            //d: '100',
            a: '00000',
            b: 'Earn',
            //c: 'The current redemption amount',
            e: 'The current earn amount:',
            //f: 'The current redemption amount:',
          }}
          onOk={() => {
            toggleBox1(false);
            console.log('ok');
          }}
          onCancel={() => {
            toggleBox1(false);
            console.log('关闭');
          }}
        />
      )} */}
      {
        showEarnings && <Earnings onCancel={() =>{
          toggleEarnings(null)
        }} data={showEarnings}/>
      }
      {
        showSuccess && <Success text={showSuccess}/>
      }
      {
        showError && <Error text={showError}/>
      }
      {
        showClose && <Close  text={showClose} onCancel={() =>{
          setShowClose('')
        }}/>
      }
      {
        showLoading && <Loading/>
      }
      {/* {showbox2 && (
        <Box2
          data={{
            d: '100',
            a: '1000',
            b: 'Redeem',
            c: 'Current staking LP',
            e: 'Current staking LP:',
            f: 'The current redemption amount:',
          }}
          onOk={() => {
            toggleBox2(false);
            console.log('ok');
          }}
          onCancel={() => {
            toggleBox2(false);
            console.log('关闭');
          }}
        />
      )} */}
    </div>
  );
}
